home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / KERNEL / ACCT.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  9KB  |  364 lines

  1. /*
  2.  *  linux/kernel/acct.c
  3.  *
  4.  *  BSD Process Accounting for Linux
  5.  *
  6.  *  Author: Marco van Wieringen <mvw@planets.elm.net>
  7.  *
  8.  *  Some code based on ideas and code from:
  9.  *  Thomas K. Dyas <tdyas@eden.rutgers.edu>
  10.  *
  11.  *  This file implements BSD-style process accounting. Whenever any
  12.  *  process exits, an accounting record of type "struct acct" is
  13.  *  written to the file specified with the acct() system call. It is
  14.  *  up to user-level programs to do useful things with the accounting
  15.  *  log. The kernel just provides the raw accounting information.
  16.  *
  17.  * (C) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V.
  18.  *
  19.  *  Plugged two leaks. 1) It didn't return acct_file into the free_filps if
  20.  *  the file happened to be read-only. 2) If the accounting was suspended
  21.  *  due to the lack of space it happily allowed to reopen it and completely
  22.  *  lost the old acct_file. 3/10/98, Al Viro.
  23.  *
  24.  *  Now we silently close acct_file on attempt to reopen. Cleaned sys_acct().
  25.  *  XTerms and EMACS are manifestations of pure evil. 21/10/98, AV.
  26.  *
  27.  *  Fixed a nasty interaction with with sys_umount(). If the accointing
  28.  *  was suspeneded we failed to stop it on umount(). Messy.
  29.  *  Another one: remount to readonly didn't stop accounting.
  30.  *    Question: what should we do if we have CAP_SYS_ADMIN but not
  31.  *  CAP_SYS_PACCT? Current code does the following: umount returns -EBUSY
  32.  *  unless we are messing with the root. In that case we are getting a
  33.  *  real mess with do_remount_sb(). 9/11/98, AV.
  34.  *
  35.  *  Fixed a bunch of races (and pair of leaks). Probably not the best way,
  36.  *  but this one obviously doesn't introduce deadlocks. Later. BTW, found
  37.  *  one race (and leak) in BSD implementation.
  38.  *  OK, that's better. ANOTHER race and leak in BSD variant. There always
  39.  *  is one more bug... TODO: move filp_open into open.c and make
  40.  *  parameters sysctl-controllable. 10/11/98, AV.
  41.  */
  42.  
  43. #include <linux/config.h>
  44. #include <linux/errno.h>
  45. #include <linux/kernel.h>
  46.  
  47. #ifdef CONFIG_BSD_PROCESS_ACCT
  48. #include <linux/mm.h>
  49. #include <linux/acct.h>
  50. #include <linux/smp_lock.h>
  51. #include <linux/file.h>
  52.  
  53. #include <asm/uaccess.h>
  54.  
  55. /*
  56.  * These constants control the amount of freespace that suspend and
  57.  * resume the process accounting system, and the time delay between
  58.  * each check.
  59.  * Turned into sysctl-controllable parameters. AV, 12/11/98
  60.  */
  61.  
  62. int acct_parm[3] = {4, 2, 30};
  63. #define RESUME        (acct_parm[0])    /* >foo% free space - resume */
  64. #define SUSPEND        (acct_parm[1])    /* <foo% free space - suspend */
  65. #define ACCT_TIMEOUT    (acct_parm[2])    /* foo second timeout between checks */
  66.  
  67. /*
  68.  * External references and all of the globals.
  69.  */
  70. void acct_timeout(unsigned long);
  71.  
  72. static volatile int acct_active = 0;
  73. static volatile int acct_needcheck = 0;
  74. static struct file *acct_file = NULL;
  75. static struct timer_list acct_timer = { NULL, NULL, 0, 0, acct_timeout };
  76. static int do_acct_process(long, struct file *);
  77.  
  78. /*
  79.  * Called whenever the timer says to check the free space.
  80.  */
  81. void acct_timeout(unsigned long unused)
  82. {
  83.     acct_needcheck = 1;
  84. }
  85.  
  86. /*
  87.  * Check the amount of free space and suspend/resume accordingly.
  88.  */
  89. static int check_free_space(struct file *file)
  90. {
  91.     mm_segment_t fs;
  92.     struct statfs sbuf;
  93.     struct super_block *sb;
  94.     int res = acct_active;
  95.     int act;
  96.  
  97.     if (!file || !acct_needcheck)
  98.         return res;
  99.  
  100.     sb = file->f_dentry->d_inode->i_sb;
  101.     if (!sb->s_op || !sb->s_op->statfs)
  102.         return res;
  103.  
  104.     fs = get_fs();
  105.     set_fs(KERNEL_DS);
  106.     /* May block */
  107.     sb->s_op->statfs(sb, &sbuf, sizeof(struct statfs));
  108.     set_fs(fs);
  109.  
  110.     if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100)
  111.         act = -1;
  112.     else if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100)
  113.         act = 1;
  114.     else
  115.         act = 0;
  116.  
  117.     /*
  118.      * If some joker switched acct_file under us we'ld better be
  119.      * silent and _not_ touch anything.
  120.      */
  121.     if (file != acct_file)
  122.         return act ? (act>0) : res;
  123.  
  124.     if (acct_active) {
  125.         if (act < 0) {
  126.             acct_active = 0;
  127.             printk(KERN_INFO "Process accounting paused\n");
  128.         }
  129.     } else {
  130.         if (act > 0) {
  131.             acct_active = 1;
  132.             printk(KERN_INFO "Process accounting resumed\n");
  133.         }
  134.     }
  135.  
  136.     del_timer(&acct_timer);
  137.     acct_needcheck = 0;
  138.     acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
  139.     add_timer(&acct_timer);
  140.     return acct_active;
  141. }
  142.  
  143. /*
  144.  *  sys_acct() is the only system call needed to implement process
  145.  *  accounting. It takes the name of the file where accounting records
  146.  *  should be written. If the filename is NULL, accounting will be
  147.  *  shutdown.
  148.  */
  149. asmlinkage int sys_acct(const char *name)
  150. {
  151.     struct file *file = NULL, *old_acct = NULL;
  152.     char *tmp;
  153.     int error = -EPERM;
  154.  
  155.     lock_kernel();
  156.     if (!capable(CAP_SYS_PACCT))
  157.         goto out;
  158.  
  159.     if (name) {
  160.         tmp = getname(name);
  161.         error = PTR_ERR(tmp);
  162.         if (IS_ERR(tmp))
  163.             goto out;
  164.         /* Difference from BSD - they don't do O_APPEND */
  165.         file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
  166.         putname(tmp);
  167.         if (IS_ERR(file)) {
  168.             error = PTR_ERR(file);
  169.             goto out;
  170.         }
  171.         error = -EACCES;
  172.         if (!S_ISREG(file->f_dentry->d_inode->i_mode)) 
  173.             goto out_err;
  174.  
  175.         error = -EIO;
  176.         if (!file->f_op->write) 
  177.             goto out_err;
  178.     }
  179.  
  180.     error = 0;
  181.     if (acct_file) {
  182.         old_acct = acct_file;
  183.         del_timer(&acct_timer);
  184.         acct_active = 0;
  185.         acct_needcheck = 0;
  186.         acct_file = NULL;
  187.     }
  188.     if (name) {
  189.         acct_file = file;
  190.         acct_needcheck = 0;
  191.         acct_active = 1;
  192.         acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
  193.         add_timer(&acct_timer);
  194.     }
  195.     if (old_acct) {
  196.         do_acct_process(0,old_acct);
  197.         filp_close(old_acct, NULL);
  198.     }
  199. out:
  200.     unlock_kernel();
  201.     return error;
  202. out_err:
  203.     filp_close(file, NULL);
  204.     goto out;
  205. }
  206.  
  207. void acct_auto_close(kdev_t dev)
  208. {
  209.     if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
  210.         sys_acct((char *)NULL);
  211. }
  212.  
  213. /*
  214.  *  encode an unsigned long into a comp_t
  215.  *
  216.  *  This routine has been adopted from the encode_comp_t() function in
  217.  *  the kern_acct.c file of the FreeBSD operating system. The encoding
  218.  *  is a 13-bit fraction with a 3-bit (base 8) exponent.
  219.  */
  220.  
  221. #define    MANTSIZE    13            /* 13 bit mantissa. */
  222. #define    EXPSIZE        3            /* Base 8 (3 bit) exponent. */
  223. #define    MAXFRACT    ((1 << MANTSIZE) - 1)    /* Maximum fractional value. */
  224.  
  225. static comp_t encode_comp_t(unsigned long value)
  226. {
  227.     int exp, rnd;
  228.  
  229.     exp = rnd = 0;
  230.     while (value > MAXFRACT) {
  231.         rnd = value & (1 << (EXPSIZE - 1));    /* Round up? */
  232.         value >>= EXPSIZE;    /* Base 8 exponent == 3 bit shift. */
  233.         exp++;
  234.     }
  235.  
  236.     /*
  237.          * If we need to round up, do it (and handle overflow correctly).
  238.          */
  239.     if (rnd && (++value > MAXFRACT)) {
  240.         value >>= EXPSIZE;
  241.         exp++;
  242.     }
  243.  
  244.     /*
  245.          * Clean it up and polish it off.
  246.          */
  247.     exp <<= MANTSIZE;        /* Shift the exponent into place */
  248.     exp += value;            /* and add on the mantissa. */
  249.     return exp;
  250. }
  251.  
  252. /*
  253.  *  Write an accounting entry for an exiting process
  254.  *
  255.  *  The acct_process() call is the workhorse of the process
  256.  *  accounting system. The struct acct is built here and then written
  257.  *  into the accounting file. This function should only be called from
  258.  *  do_exit().
  259.  */
  260. #define KSTK_EIP(stack) (((unsigned long *)(stack))[1019])
  261. #define KSTK_ESP(stack) (((unsigned long *)(stack))[1022])
  262.  
  263. /*
  264.  *  do_acct_process does all actual work.
  265.  */
  266. static int do_acct_process(long exitcode, struct file *file)
  267. {
  268.     struct acct ac;
  269.     mm_segment_t fs;
  270.     unsigned long vsize;
  271.     struct inode *inode;
  272.  
  273.     /*
  274.      * First check to see if there is enough free_space to continue
  275.      * the process accounting system.
  276.      */
  277.     if (!file)
  278.         return 0;
  279.     file->f_count++;
  280.     if (!check_free_space(file)) {
  281.         fput(file);
  282.         return 0;
  283.     }
  284.  
  285.     /*
  286.      * Fill the accounting struct with the needed info as recorded
  287.      * by the different kernel functions.
  288.      */
  289.     memset((caddr_t)&ac, 0, sizeof(struct acct));
  290.  
  291.     strncpy(ac.ac_comm, current->comm, ACCT_COMM);
  292.     ac.ac_comm[ACCT_COMM - 1] = '\0';
  293.  
  294.     ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
  295.     ac.ac_etime = encode_comp_t(jiffies - current->start_time);
  296.     ac.ac_utime = encode_comp_t(current->times.tms_utime);
  297.     ac.ac_stime = encode_comp_t(current->times.tms_stime);
  298.     ac.ac_uid = current->uid;
  299.     ac.ac_gid = current->gid;
  300.     ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0;
  301.  
  302.     ac.ac_flag = 0;
  303.     if (current->flags & PF_FORKNOEXEC)
  304.         ac.ac_flag |= AFORK;
  305.     if (current->flags & PF_SUPERPRIV)
  306.         ac.ac_flag |= ASU;
  307.     if (current->flags & PF_DUMPCORE)
  308.         ac.ac_flag |= ACORE;
  309.     if (current->flags & PF_SIGNALED)
  310.         ac.ac_flag |= AXSIG;
  311.  
  312.     vsize = 0;
  313.     if (current->mm) {
  314.         struct vm_area_struct *vma = current->mm->mmap;
  315.         while (vma) {
  316.             vsize += vma->vm_end - vma->vm_start;
  317.             vma = vma->vm_next;
  318.         }
  319.     }
  320.     vsize = vsize / 1024;
  321.     ac.ac_mem = encode_comp_t(vsize);
  322.     ac.ac_io = encode_comp_t(0 /* current->io_usage */);    /* %% */
  323.     ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
  324.     ac.ac_minflt = encode_comp_t(current->min_flt);
  325.     ac.ac_majflt = encode_comp_t(current->maj_flt);
  326.     ac.ac_swaps = encode_comp_t(current->nswap);
  327.     ac.ac_exitcode = exitcode;
  328.  
  329.     /*
  330.          * Kernel segment override to datasegment and write it
  331.          * to the accounting file.
  332.          */
  333.     fs = get_fs();
  334.     set_fs(KERNEL_DS);
  335.     inode = file->f_dentry->d_inode;
  336.     down(&inode->i_sem);
  337.     file->f_op->write(file, (char *)&ac,
  338.                    sizeof(struct acct), &file->f_pos);
  339.     up(&inode->i_sem);
  340.     set_fs(fs);
  341.     fput(file);
  342.     return 0;
  343. }
  344.  
  345. /*
  346.  * acct_process - now just a wrapper around do_acct_process
  347.  */
  348. int acct_process(long exitcode)
  349. {
  350.     return do_acct_process(exitcode, acct_file);
  351. }
  352.  
  353. #else
  354. /*
  355.  * Dummy system call when BSD process accounting is not configured
  356.  * into the kernel.
  357.  */
  358.  
  359. asmlinkage int sys_acct(const char * filename)
  360. {
  361.     return -ENOSYS;
  362. }
  363. #endif
  364.